/*=============================================================================
  ShaderTemplate.cpp : implementation of the Shaders templates support.
  Copyright (c) 2001 Crytek Studios. All Rights Reserved.

  Revision history:
    * Created by Honich Andrey

=============================================================================*/

#include "StdAfx.h"
#include "I3DEngine.h"
#include "CryHeaders.h"
#include "StringUtils.h"								// stristr()

#if !defined(__SPU__)
#if defined(WIN32) || defined(WIN64)
#include <direct.h>
#include <io.h>
#elif defined(LINUX)

#endif

//===============================================================================

void SRenderShaderResources::ConvertToInputResource(SInputShaderResources *pDst)
{
  pDst->m_ResFlags = m_ResFlags;
  pDst->m_AlphaRef = m_AlphaRef;
  pDst->m_FurAmount = m_FurAmount;
	pDst->m_CloakAmount = m_CloakAmount;
  pDst->m_SortPrio = m_SortPrio;
  if (m_pDeformInfo)
    pDst->m_DeformInfo = *m_pDeformInfo;
  else
    pDst->m_DeformInfo.m_eType = eDT_Unknown;
  if (m_Constants[eHWSC_Pixel].size())
  {
    ColorF *pSrc = (ColorF *)&m_Constants[eHWSC_Pixel][0];
    pDst->m_LMaterial.m_Diffuse = pSrc[PS_DIFFUSE_COL];
    pDst->m_LMaterial.m_Specular = pSrc[PS_SPECULAR_COL];
    pDst->m_LMaterial.m_Emission = pSrc[PS_EMISSIVE_COL];
    pDst->m_LMaterial.m_SpecShininess = pSrc[PS_SPECULAR_COL][3] * 255.0f;
    pDst->m_Opacity = pSrc[PS_DIFFUSE_COL][3];
    pDst->m_GlowAmount = pSrc[PS_EMISSIVE_COL][3];
  }

  pDst->m_TexturePath = m_TexturePath;
  if (m_pDeformInfo)
    pDst->m_DeformInfo = *m_pDeformInfo;
  
  if( m_pDetailDecalInfo )
    pDst->m_DetailDecalInfo = *m_pDetailDecalInfo;
  else
    pDst->m_DetailDecalInfo.Reset();

  for (int i=0; i<EFTT_MAX; i++)
  {
    if (m_Textures[i])
    {
      pDst->m_Textures[i] = *m_Textures[i];
    }
    else
    {
      pDst->m_Textures[i].Reset();
    }
  }
}

void SRenderShaderResources::ExportModificators(IRenderShaderResources *pT, CRenderObject *pObj)
{
  SRenderShaderResources *pTrg = (SRenderShaderResources *)pT;
  if (m_Constants[eHWSC_Vertex].size() > PS_SPECULAR_COL)
  {
    SRenderObjData *pD = gRenDev->EF_GetObjData(pObj, true);
    uint32 nSize = max(m_Constants[eHWSC_Vertex].size(), pTrg->m_Constants[eHWSC_Vertex].size());
    pD->m_Constants.resize(nSize);
    for (uint32 i=0; i<nSize; i++)
    {
      if ((i <= PS_SPECULAR_COL || i >= 4) && i < pTrg->m_Constants[eHWSC_Vertex].size())
        pD->m_Constants[i] = pTrg->m_Constants[eHWSC_Vertex][i];
      else
      if (i < m_Constants[eHWSC_Vertex].size())
        pD->m_Constants[i] = m_Constants[eHWSC_Vertex][i];
    }
  }
}

size_t SRenderShaderResources::GetResourceMemoryUsage(ICrySizer*	pSizer)
{
	size_t	nCurrentElement(0);
	size_t	nCurrentElementSize(0);
	size_t	nTotalSize(0);

	SIZER_COMPONENT_NAME(pSizer, "SRenderShaderResources");
	for (nCurrentElement=0; nCurrentElement<EFTT_MAX; ++nCurrentElement)
	{
		SEfResTexture*&	rpTexture=m_Textures[nCurrentElement];
		if (rpTexture)
		{
			if (rpTexture->m_Sampler.m_pITex)
			{
				nCurrentElementSize=rpTexture->m_Sampler.m_pITex->GetDataSize();
				pSizer->AddObject(rpTexture->m_Sampler.m_pITex,nCurrentElementSize);
				nTotalSize+=nCurrentElementSize;
				IResourceCollector* pColl = pSizer->GetResourceCollector();
				if (pColl)
				{
					pColl->AddResource(rpTexture->m_Sampler.m_pITex->GetName(),nCurrentElementSize);
				}
			}
		}		
	}

	return nTotalSize;

	//TArray<struct SHRenderTarget *> m_RTargets;
	//SSkyInfo *m_pSky;
	//SDeformInfo *m_pDeformInfo;  
	//SDetailDecalInfo *m_pDetailDecalInfo;
	//DynArray<Vec4> m_Constants[3];
}

void SRenderShaderResources::Release()
{
#ifdef NULL_RENDERER
  return;
#endif
//  if (!CryInterlockedDecrement(&m_nRefCounter)) // is checked inside render thread
  {
    if (gRenDev && gRenDev->m_pRT)
      gRenDev->m_pRT->RC_ReleaseShaderResource(this);
	else
		assert(0); //SRenderShaderResources: leaks or/and invalid usage
  }
}

void SRenderShaderResources::RT_Release()
{
	if( !CryInterlockedDecrement(&m_nRefCounter) )
	{
		delete this;
	}
}

void SRenderShaderResources::Cleanup()
{
  //assert(gRenDev->m_pRT->IsRenderThread());

  for (int i=0; i<EFTT_MAX; i++)
  {
    SAFE_DELETE(m_Textures[i]);
  }
  SAFE_DELETE(m_pDeformInfo);
  SAFE_DELETE(m_pDetailDecalInfo);
	if (m_pSky)
	{
		for (size_t i = 0; i < sizeof(m_pSky->m_SkyBox) / sizeof(m_pSky->m_SkyBox[0]); ++ i)
		{
			SAFE_RELEASE(m_pSky->m_SkyBox[i]);
		}
		SAFE_DELETE(m_pSky);
	}
  ReleaseConstants();

  // not thread safe main thread can potentially access this destroyed entry in mfCreateShaderResources()
  // (if flushing of unloaded textures (UnloadLevel) is not complete before pre-loading of new materials)
  if (CShader::m_ShaderResources_known.Num() > m_Id && CShader::m_ShaderResources_known[m_Id] == this)
	{
		CShader::m_ShaderResources_known[m_Id] = NULL;
	}
}

SRenderShaderResources::~SRenderShaderResources()
{
	Cleanup();

	if (gRenDev->m_RP.m_pShaderResources == this)
	{
		gRenDev->m_RP.m_pShaderResources = NULL;
	}
}

SRenderShaderResources::SRenderShaderResources(SInputShaderResources *pSrc)
{
  Reset();

  m_szMaterialName = pSrc->m_szMaterialName;
  m_TexturePath = pSrc->m_TexturePath;
  m_ResFlags = pSrc->m_ResFlags;
  m_AlphaRef = pSrc->m_AlphaRef;
  m_FurAmount = pSrc->m_FurAmount;
	m_HeatAmount = pSrc->m_HeatAmount;
	m_CloakAmount = pSrc->m_CloakAmount;
  m_SortPrio = pSrc->m_SortPrio;
  m_ShaderParams = pSrc->m_ShaderParams;
  if (pSrc->m_DeformInfo.m_eType)
  {
    m_pDeformInfo = new SDeformInfo;
    *m_pDeformInfo = pSrc->m_DeformInfo;
  }
  if( (m_ResFlags&MTL_FLAG_DETAIL_DECAL) )
  {
    m_pDetailDecalInfo = new SDetailDecalInfo;
    *m_pDetailDecalInfo = pSrc->m_DetailDecalInfo;
  }

  SetInputLM(pSrc->m_LMaterial);
  Vec4 *pDst = &m_Constants[eHWSC_Pixel][0];
  pDst[PS_DIFFUSE_COL][3] = pSrc->m_Opacity;
  pDst[PS_EMISSIVE_COL][3] = pSrc->m_GlowAmount;

  for (int i=0; i<EFTT_MAX; i++)
  {
    if (pSrc && (!pSrc->m_Textures[i].m_Name.empty() || pSrc->m_Textures[i].m_Sampler.m_pTex))
    {
      if (!m_Textures[i])
        AddTextureMap(i);
			assert(m_Textures[i]);
      pSrc->m_Textures[i].CopyTo(m_Textures[i]);
    }
    else
    {
      if (m_Textures[i])
        m_Textures[i]->Reset();
      m_Textures[i] = NULL;
    }
  }
}

SRenderShaderResources& SRenderShaderResources::operator=(const SRenderShaderResources& src)
{
	Cleanup();
  SBaseShaderResources::operator = (src);
  int i;
  for (i=0; i<EFTT_MAX; i++)
  {
    if (!src.m_Textures[i])
      continue;
    AddTextureMap(i);
    *m_Textures[i] = *src.m_Textures[i];
  }
  for (i=0; i<2; i++)
  {
    m_Constants[i] = src.m_Constants[i];
  }
  m_IdGroup = src.m_IdGroup;
  return *this;
}

SRenderShaderResources *SRenderShaderResources::Clone()
{
  SRenderShaderResources *pSR = new SRenderShaderResources();
  *pSR = *this;
  pSR->m_nRefCounter = 1;
  for (uint32 i=0; i<CShader::m_ShaderResources_known.Num(); i++)
  {
    if (!CShader::m_ShaderResources_known[i])
    {
      pSR->m_Id = i;
      CShader::m_ShaderResources_known[i] = pSR;
      return pSR;
    }
  }
  if (CShader::m_ShaderResources_known.Num() >= MAX_REND_SHADER_RES)
  {
    Warning("ERROR: CShaderMan::mfCreateShaderResources: MAX_REND_SHADER_RESOURCES hit");
		pSR->Release();
    return CShader::m_ShaderResources_known[1];
  }
  pSR->m_Id = CShader::m_ShaderResources_known.Num();
	ScopedSwitchToGlobalHeap globalHeap;
  CShader::m_ShaderResources_known.AddElem(pSR);

  return pSR;
}

void SRenderShaderResources::SetInputLM(const CInputLightMaterial& lm)
{
  if (!m_Constants[eHWSC_Pixel].size())
    m_Constants[eHWSC_Pixel].resize(NUM_PS_PM);

  ColorF *pDst = (ColorF *)&m_Constants[eHWSC_Pixel][0];
	//workaround for ps3-compiler bug
	uint32 Idx	=	PS_DIFFUSE_COL;
  pDst[Idx].r = lm.m_Diffuse.r;
  pDst[Idx].g = lm.m_Diffuse.g;
  pDst[Idx].b = lm.m_Diffuse.b;
	  // Apply shading to custom environment maps (and skip for nearest cubemap feature since these are based on real scene don't need shading) 
  const float fShadeEnvCM = (m_Textures[EFTT_ENV] && m_Textures[EFTT_ENV]->m_Sampler.m_eTexType == eTT_NearestCube)? 0.0f : 1.0f;
  pDst[Idx].a = fShadeEnvCM;

	Idx	=	PS_SPECULAR_COL;
  pDst[Idx] = lm.m_Specular;
  pDst[Idx][3] = lm.m_SpecShininess / 255.0f;

	Idx	=	PS_EMISSIVE_COL;
  pDst[Idx].r = lm.m_Emission.r;
  pDst[Idx].g = lm.m_Emission.g;
  pDst[Idx].b = lm.m_Emission.b;
	pDst[Idx].a = 0.0f;

  if (!m_Constants[eHWSC_Vertex].size())
    m_Constants[eHWSC_Vertex].resize(NUM_VS_PM);
	Idx	=	VS_DIFFUSE_COL;
  pDst = (ColorF *)&m_Constants[eHWSC_Vertex][0];
  pDst[Idx].r = lm.m_Diffuse.r;
  pDst[Idx].g = lm.m_Diffuse.g;
  pDst[Idx].b = lm.m_Diffuse.b;
	pDst[Idx].a = fShadeEnvCM;

	Idx	=	VS_SPECULAR_COL;
  pDst[Idx] = lm.m_Specular;
  pDst[Idx][3] = lm.m_SpecShininess / 255.0f;
}

void SRenderShaderResources::ToInputLM(CInputLightMaterial& lm)
{
  if (!m_Constants[eHWSC_Pixel].size())
    return;
  ColorF *pDst = (ColorF *)&m_Constants[eHWSC_Pixel][0];
  lm.m_Diffuse = pDst[PS_DIFFUSE_COL];
  lm.m_Specular = pDst[PS_SPECULAR_COL];
  lm.m_Emission = pDst[PS_EMISSIVE_COL];
  lm.m_SpecShininess = pDst[PS_SPECULAR_COL][3] * 255.0f;
}
#endif

static ColorF sColBlack = Col_Black;














#if !defined(__SPU__)
ColorF& SRenderShaderResources::GetDiffuseColor()
{
  if (!m_Constants[eHWSC_Pixel].size())
    return sColBlack;
  ColorF *pDst = (ColorF *)&m_Constants[eHWSC_Pixel][0];
  return pDst[PS_DIFFUSE_COL];
}

ColorF& SRenderShaderResources::GetSpecularColor()
{
  if (!m_Constants[eHWSC_Pixel].size())
    return sColBlack;
  ColorF *pDst = (ColorF *)&m_Constants[eHWSC_Pixel][0];
  return pDst[PS_SPECULAR_COL];
}

ColorF& SRenderShaderResources::GetEmissiveColor()
{
  if (!m_Constants[eHWSC_Pixel].size())
    return sColBlack;
  ColorF *pDst = (ColorF *)&m_Constants[eHWSC_Pixel][0];
  return pDst[PS_EMISSIVE_COL];
}

float& SRenderShaderResources::GetSpecularShininess()
{
  if (!m_Constants[eHWSC_Pixel].size())
    return sColBlack.a;
  ColorF *pDst = (ColorF *)&m_Constants[eHWSC_Pixel][0];
  return pDst[PS_SPECULAR_COL][3];
}

void SRenderShaderResources::UpdateConstants(IShader *pISH)
{
  if (gRenDev && gRenDev->m_pRT)
    gRenDev->m_pRT->RC_UpdateMaterialConstants(this, pISH); 
}


SRenderShaderResources *CShaderMan::mfCreateShaderResources(const SInputShaderResources *Res, bool bShare)
{
  uint32 i, j;

  SInputShaderResources RS;
  RS = *Res;

  for (i=0; i<EFTT_MAX; i++)
  {
    SAFE_RELEASE(RS.m_Textures[i].m_Sampler.m_pTex);
    //if (RS.m_Textures[i].m_TexFlags & TEXMAP_NOMIPMAP)
    //  RS.m_Textures[i].m_Sampler.m_nFlags |= FSAMP_NOMIPS;

    if (i == EFTT_DETAIL_OVERLAY && !RS.m_Textures[i].m_Name.empty())
    {
      RS.m_Textures[i].m_Sampler.m_pTex = mfLoadResourceTexture(RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str(), RS.m_Textures[i].m_Sampler.GetTexFlags(), eTT_2D, &RS.m_Textures[i]);
      if (!RS.m_Textures[i].m_Sampler.m_pTex->IsTextureLoaded())
      {
        //TextureWarning( RS.m_Textures[i].m_Name.c_str(),"Error: CShaderMan::mfCreateShaderResources: Couldn't find detail texture '%s' in path '%s'", RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str());
        RS.m_Textures[i].m_Sampler.m_pTex = mfLoadResourceTexture("EngineAssets/TextureMsg/ReplaceMe.tif", RS.m_TexturePath.c_str(), RS.m_Textures[i].m_Sampler.GetTexFlags(), eTT_2D, &RS.m_Textures[i]);
      }
    }

    if (i == EFTT_DECAL_OVERLAY && !RS.m_Textures[i].m_Name.empty())
    {
      RS.m_Textures[i].m_Sampler.m_pTex = mfLoadResourceTexture(RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str(), RS.m_Textures[i].m_Sampler.GetTexFlags(), eTT_2D, &RS.m_Textures[i]);
      //if (!RS.m_Textures[i].m_Sampler.m_pTex->IsTextureLoaded())
        //TextureWarning( RS.m_Textures[i].m_Name.c_str(),"Error: CShaderMan::mfCreateShaderResources: Couldn't find decal texture '%s' in path '%s'", RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str());
    }

    if (i == EFTT_SUBSURFACE && !RS.m_Textures[i].m_Name.empty())
    {
      RS.m_Textures[i].m_Sampler.m_pTex = mfLoadResourceTexture(RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str(), RS.m_Textures[i].m_Sampler.GetTexFlags(), eTT_2D, &RS.m_Textures[i]);
      //if (!RS.m_Textures[i].m_Sampler.m_pTex->IsTextureLoaded())
        //TextureWarning( RS.m_Textures[i].m_Name.c_str(),"Error: CShaderMan::mfCreateShaderResources: Couldn't find subsurface texture '%s' in path '%s'", RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str());
    }
    
    if (i == EFTT_CUSTOM && !RS.m_Textures[i].m_Name.empty())
    {
      RS.m_Textures[i].m_Sampler.m_pTex = mfLoadResourceTexture(RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str(), RS.m_Textures[i].m_Sampler.GetTexFlags(), eTT_2D, &RS.m_Textures[i]);      
      //if (!RS.m_Textures[i].m_Sampler.m_pTex->IsTextureLoaded())
        //TextureWarning( RS.m_Textures[i].m_Name.c_str(),"Error: CShaderMan::mfCreateShaderResources: Couldn't find custom texture '%s' in path '%s'", RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str());
    }    

    if (i == EFTT_CUSTOM_SECONDARY && !RS.m_Textures[i].m_Name.empty())
    {
      RS.m_Textures[i].m_Sampler.m_pTex = mfLoadResourceTexture(RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str(), RS.m_Textures[i].m_Sampler.GetTexFlags(), eTT_2D, &RS.m_Textures[i]);      
      //if (!RS.m_Textures[i].m_Sampler.m_pTex->IsTextureLoaded())
        //TextureWarning( RS.m_Textures[i].m_Name.c_str(),"Error: CShaderMan::mfCreateShaderResources: Couldn't find custom secondary texture '%s' in path '%s'", RS.m_Textures[i].m_Name.c_str(), RS.m_TexturePath.c_str());
    }    

  }

  int nFree = -1;
  for (i=1; i<CShader::m_ShaderResources_known.Num(); i++)
  {
    // not thread safe can be modified from render thread in SRenderShaderResources dtor ()
    // (if flushing of unloaded textures (UnloadLevel) is not complete before pre-loading of new materials)
    SRenderShaderResources *pSR = CShader::m_ShaderResources_known[i];
    if (!pSR)
    {
      nFree = i;
      if (!bShare || Res->m_ShaderParams.size())
        break;
      continue;
    }
    if (!bShare || Res->m_ShaderParams.size())
      continue;
    if (RS.m_ResFlags == pSR->m_ResFlags && RS.m_Opacity == pSR->m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][3] && 
				RS.m_GlowAmount == pSR->Glow() &&
				RS.m_AlphaRef == pSR->m_AlphaRef && !stricmp(RS.m_TexturePath.c_str(), pSR->m_TexturePath.c_str()))
    {
      if ((!pSR->m_pDeformInfo && !RS.m_DeformInfo.m_eType) || (pSR->m_pDeformInfo && *pSR->m_pDeformInfo == RS.m_DeformInfo))
      {
        for (j=0; j<EFTT_MAX; j++)
        {
          if (!pSR->m_Textures[j] || pSR->m_Textures[j]->m_Name.empty())
          {
            if (RS.m_Textures[j].m_Name.empty())
              continue;
            break;
          }
          else
          if (RS.m_Textures[j].m_Name.empty())
            break;
          if (RS.m_Textures[j] != *pSR->m_Textures[j])
            break;
        }
        if (j == EFTT_MAX)
        {
          pSR->AddRef();
          return pSR;
        }
      }
    }
  }

  SRenderShaderResources *pSR = new SRenderShaderResources(&RS);
  pSR->m_nRefCounter = 1;
  if (!CShader::m_ShaderResources_known.Num())
  {
		ScopedSwitchToGlobalHeap globalHeap;
    CShader::m_ShaderResources_known.AddIndex(1);
    SRenderShaderResources *pSRNULL = new SRenderShaderResources;
    pSRNULL->m_nRefCounter = 1;
    CShader::m_ShaderResources_known[0] = pSRNULL;
  }
  else
  if (nFree<0 && CShader::m_ShaderResources_known.Num() >= MAX_REND_SHADER_RES)
  {
    Warning("ERROR: CShaderMan::mfCreateShaderResources: MAX_REND_SHADER_RESOURCES hit");
		pSR->Release();
    return CShader::m_ShaderResources_known[1];
  }
  if (nFree > 0)
  {
    pSR->m_Id = nFree;
    pSR->m_IdGroup = pSR->m_Id;
    CShader::m_ShaderResources_known[nFree] = pSR;
  }
  else
  {
		ScopedSwitchToGlobalHeap globalHeap;
    pSR->m_Id = CShader::m_ShaderResources_known.Num();
    pSR->m_IdGroup = pSR->m_Id;
    CShader::m_ShaderResources_known.AddElem(pSR);
  }

  return pSR;
}


void SShaderItem::PostLoad()
{
  CShader *pSH = (CShader *)m_pShader;
  SRenderShaderResources *pR = (SRenderShaderResources *)m_pShaderResources;

  if (pSH->m_Flags2 & EF2_PREPR_GENSPRITES)
    m_nPreprocessFlags |= FSPR_GENSPRITES | FB_PREPROCESS;
  if (pSH->m_Flags2 & EF2_PREPR_GENCLOUDS)
    m_nPreprocessFlags |= FSPR_GENCLOUDS;
  if (pSH->m_Flags2 & EF2_PREPR_SCANWATER)
    m_nPreprocessFlags |= FSPR_SCANTEXWATER | FB_PREPROCESS;

  m_nPreprocessFlags |= FB_GENERAL;
  const SShaderTechnique *pTech = GetTechnique();
  if (pR)
  {
    pR->PostLoad(pSH);
		//if (pTech)
		//{
		//	for (int i=0; i<pTech->m_RTargets.Num(); ++i)
		//		SAFE_DELETE(pTech->m_RTargets[i]);
		//	pTech->m_RTargets.Reset();
		//}
    for (int i=0; i<EFTT_MAX; i++)
    {
      if (!pR->m_Textures[i] || !pR->m_Textures[i]->m_Sampler.m_pTarget)
        continue;

      if (gRenDev->m_RP.m_eQuality == eRQ_Low)
      {
				STexSamplerRT& sampler(pR->m_Textures[i]->m_Sampler);
        if (sampler.m_eTexType == eTT_AutoCube)
          sampler.m_eTexType = eTT_Cube;
        else if (sampler.m_eTexType == eTT_Auto2D && !sampler.m_pDynTexSource)
          sampler.m_eTexType = eTT_2D;
      }

      if (pR->m_Textures[i]->m_Sampler.m_eTexType == eTT_AutoCube || pR->m_Textures[i]->m_Sampler.m_eTexType == eTT_Auto2D)
        pR->m_ResFlags |= MTL_FLAG_NOTINSTANCED;
      pR->m_RTargets.AddElem(pR->m_Textures[i]->m_Sampler.m_pTarget);
      if (pR->m_Textures[i]->m_Sampler.m_eTexType == eTT_AutoCube)
        m_nPreprocessFlags |= FSPR_SCANCM;
      else
      if (pR->m_Textures[i]->m_Sampler.m_eTexType == eTT_Auto2D)
        m_nPreprocessFlags |= FSPR_SCANTEX;
    }
  }
  if (pTech && pTech->m_Passes.Num() && (pTech->m_Passes[0].m_RenderState & GS_ALPHATEST_MASK))
  {
    if (pR && !pR->m_AlphaRef)
      pR->m_AlphaRef = 0.5f;
  }

  // Update persistent batch flags
  if (pTech)
  {
    if (pTech->m_nTechnique[TTYPE_Z] > 0)
      m_nPreprocessFlags |= FB_Z;

    if (!(pTech->m_Flags & FHF_POSITION_INVARIANT) && ((pTech->m_Flags & FHF_TRANSPARENT) || (pR && pR->Opacity() < 1.0f)))
      m_nPreprocessFlags |= FB_TRANSPARENT; 

    if (gRenDev->m_bWaterCaustics && pTech->m_nTechnique[TTYPE_CAUSTICS] > 0 && (!CRenderer::CV_r_watercausticsdeferred || (m_nPreprocessFlags & FB_TRANSPARENT)))
      m_nPreprocessFlags |= FB_CAUSTICS;

    if (pTech->m_nTechnique[TTYPE_GLOWPASS] > 0 && pR->Glow())
      m_nPreprocessFlags |= FB_GLOW;

    if (pR && (pR->m_ResFlags & MTL_FLAG_SCATTER))
      m_nPreprocessFlags |= FB_SCATTER;

		if ((pSH->m_Flags2 & EF2_SKINPASS))
			m_nPreprocessFlags |= FB_SKIN;

		if (CRenderer::CV_r_SoftAlphaTest && pTech->m_nTechnique[TTYPE_SOFTALPHATESTPASS] > 0)
		  m_nPreprocessFlags |= FB_SOFTALPHATEST;
		
    if (CRenderer::CV_r_refraction && (pSH->m_Flags & EF_REFRACTIVE))
      m_nPreprocessFlags |= FB_TRANSPARENT;

    if (pTech->m_nTechnique[TTYPE_EFFECTLAYER] > 0 && pR->m_Textures[EFTT_CUSTOM] && pR->m_Textures[EFTT_CUSTOM_SECONDARY])
      m_nPreprocessFlags |= FB_LAYER_EFFECT;
  }

  if (pTech)
    m_nPreprocessFlags |= pTech->m_nPreprocessFlags;

  if (m_nPreprocessFlags & FSPR_MASK)
    m_nPreprocessFlags |= FB_PREPROCESS;

  //pR->UpdateConstants(m_pShader);
}

void SRenderShaderResources::SetShaderParams(SInputShaderResources *pDst, IShader *pSH)
{
  ReleaseParams();
  m_ShaderParams = pDst->m_ShaderParams;

  gRenDev->m_pRT->RC_UpdateMaterialConstants(this, pSH);
}


//=================================================================================================

CTexture *CShaderMan::mfCheckTemplateTexName(const char *mapname, ETEX_Type eTT)
{
  CTexture *TexPic = NULL;
  if (mapname[0] != '$')
    return NULL;
  
  if (!stricmp(mapname, "$ScreenShadowMap"))
    TexPic = CTexture::s_ptexScreenShadowMap[0];
  else
  if (!strnicmp(mapname, "$Flare", 6))
    TexPic = CTexture::s_ptexFlare;
  else
  if (!strnicmp(mapname, "$ShadowID", 9))
  {
    int n = atoi(&mapname[9]);
    TexPic = CTexture::s_ptexShadowID[n];
  }
  else
  if (!stricmp(mapname, "$FromRE") || !stricmp(mapname, "$FromRE0"))
    TexPic = CTexture::s_ptexFromRE[0];
  else
  if (!stricmp(mapname, "$FromRE1"))
    TexPic = CTexture::s_ptexFromRE[1];
  else
  if (!stricmp(mapname, "$FromRE2"))
    TexPic = CTexture::s_ptexFromRE[2];
  else
  if (!stricmp(mapname, "$FromRE3"))
    TexPic = CTexture::s_ptexFromRE[3];
	else
  if (!stricmp(mapname, "$FromRE4"))
		TexPic = CTexture::s_ptexFromRE[4];
  else
	if (!stricmp(mapname, "$FromRE5"))
		TexPic = CTexture::s_ptexFromRE[5];
	else
	if (!stricmp(mapname, "$FromRE6"))
		TexPic = CTexture::s_ptexFromRE[6];
	else
	if (!stricmp(mapname, "$FromRE7"))
		TexPic = CTexture::s_ptexFromRE[7];
	else
	if (!stricmp(mapname, "$FromSF0"))
		TexPic = CTexture::s_ptexText_FromSF[0];
	else
	if (!stricmp(mapname, "$FromSF1"))
		TexPic = CTexture::s_ptexText_FromSF[1];
	else
	if (!stricmp(mapname, "$VolObj_Density"))
		TexPic = CTexture::s_ptexVolObj_Density;
	else
	if (!stricmp(mapname, "$VolObj_Shadow"))
		TexPic = CTexture::s_ptexVolObj_Shadow;
	else
	if (!stricmp(mapname, "$ColorChart"))
		TexPic = CTexture::s_ptexColorChart;
	else
  if (!stricmp(mapname, "$FromObj"))
    TexPic = CTexture::s_ptexFromObj;
	else
	if (!stricmp(mapname, "$FromObjCM"))
		TexPic = CTexture::s_ptexFromObjCM;
  else
  if (!stricmp(mapname, "$FromLight"))
    TexPic = CTexture::s_ptexFromLight;
  else
  if (!strnicmp(mapname, "$White", 6))
    TexPic = CTexture::s_ptexWhite;
  else
  if (!strnicmp(mapname, "$RT_2D", 6))
  {
    TexPic = CTexture::s_ptexRT_2D;
  }
  else
  if (!strnicmp(mapname, "$RT_Cube", 8) || !strnicmp(mapname, "$RT_CM", 6))
    TexPic = CTexture::s_ptexRT_CM;
  else
  if (!stricmp(mapname, "$Diffuse"))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_DIFFUSE];
  else
  if (!stricmp(mapname, "$DecalOverlay"))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_DECAL_OVERLAY];
  else
  if (!stricmp(mapname, "$Detail"))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_DETAIL_OVERLAY];
  else
  if (!stricmp(mapname, "$Opacity"))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_OPACITY];
  else
  if (!strnicmp(mapname, "$BumpDiffuse", 12))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_BUMP_DIFFUSE];
  else
  if (!strnicmp(mapname, "$BumpHeight", 10))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_BUMP_HEIGHT];
  else
  if (!strnicmp(mapname, "$Bump", 5))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_BUMP];
  else
  if (!strnicmp(mapname, "$Subsurface", 11))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_SUBSURFACE];
  else
  if (!stricmp(mapname, "$CustomMap"))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_CUSTOM];
  else
  if (!stricmp(mapname, "$CustomSecondaryMap"))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_CUSTOM_SECONDARY];
  else
  if (!stricmp(mapname, "$Cubemap") || !strnicmp(mapname, "$Env", 4))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_ENV];
  else
  if (!strnicmp(mapname, "$Gloss", 6))
    TexPic = &CTexture::s_ShaderTemplates[EFTT_GLOSS];
  else
	if (!stricmp(mapname, "$PrevFrameScaled"))
		TexPic = CTexture::s_ptexPrevFrameScaled;	
  else
  if (!stricmp(mapname, "$BackBuffer"))
    TexPic = CTexture::s_ptexBackBuffer;
  else
  if (!stricmp(mapname, "$BackBufferScaled_d2"))
    TexPic = CTexture::s_ptexBackBufferScaled[0];
  else
  if (!stricmp(mapname, "$BackBufferScaled_d4"))
    TexPic = CTexture::s_ptexBackBufferScaled[1];
  else
  if (!stricmp(mapname, "$BackBufferScaled_d8"))
    TexPic = CTexture::s_ptexBackBufferScaled[2];
	else
	if (!stricmp(mapname, "$BackBufferScaled_d16"))
		TexPic = CTexture::s_ptexBackBufferScaled[3];
  else
  if (!stricmp(mapname, "$HDR_BackBuffer"))
    TexPic = CTexture::s_ptexSceneTarget;
  else
  if (!stricmp(mapname, "$HDR_BackBufferScaled_d2"))
    TexPic = CTexture::s_ptexHDRTargetScaled[0];
  else
  if (!stricmp(mapname, "$HDR_BackBufferScaled_d4"))
    TexPic = CTexture::s_ptexHDRTargetScaled[1];
  else
  if (!stricmp(mapname, "$HDR_BackBufferScaled_d8"))
    TexPic = CTexture::s_ptexHDRTargetScaled[2];
  else
  if (!stricmp(mapname, "$ZTarget"))
    TexPic = CTexture::s_ptexZTarget;
  else
  if (!stricmp(mapname, "$ZTargetMS"))
    TexPic = CTexture::s_ptexZTargetMS;
	else
  if (!stricmp(mapname, "$ZTargetScaled"))
    TexPic = CTexture::s_ptexZTargetScaled;
  else
  if (!stricmp(mapname, "$ScatterLayer"))
    TexPic = CTexture::s_ptexScatterLayer;
  else
  if (!stricmp(mapname, "$SceneTarget"))
    TexPic = CTexture::s_ptexSceneTarget;
  else
  if (!stricmp(mapname, "$CloudsLM"))
    TexPic = CTexture::s_ptexCloudsLM;
  else
  if (!stricmp(mapname, "$WaterVolumeDDN"))
    TexPic = CTexture::s_ptexWaterVolumeDDN;
  else
  if (!stricmp(mapname, "$SceneNormalsMap"))
    TexPic = CTexture::s_ptexSceneNormalsMap;
	else
		if (!stricmp(mapname, "$SceneNormalsMapMS"))
			TexPic = CTexture::s_ptexSceneNormalsMapMS;
  else
	if (!stricmp(mapname, "$SceneNormalsBent"))
		TexPic = CTexture::s_ptexSceneNormalsBent;
	else
  if (!stricmp(mapname, "$SceneDiffuseAcc"))
    TexPic = CTexture::s_ptexCurrentSceneDiffuseAccMap;
	else
	if (!stricmp(mapname, "$SceneSpecularAcc"))
		TexPic = CTexture::s_ptexSceneSpecularAccMap;
	else
	if (!stricmp(mapname, "$SceneDiffuseAccMS"))
		TexPic = CTexture::s_ptexSceneDiffuseAccMapMS;
	else
	if (!stricmp(mapname, "$SceneSpecularAccMS"))
		TexPic = CTexture::s_ptexSceneSpecularAccMapMS;
  else
	if (!stricmp(mapname, "$LPV_Red_RT"))
		TexPic = CTexture::s_ptexLPV_RTs[0];
	else
	if (!stricmp(mapname, "$LPV_Green_RT"))
		TexPic = CTexture::s_ptexLPV_RTs[1];
	else
	if (!stricmp(mapname, "$LPV_Blue_RT"))
		TexPic = CTexture::s_ptexLPV_RTs[2];
	else
	if (!stricmp(mapname, "$RSM_Flux_RT"))
		TexPic = CTexture::s_ptexRSMFlux;
	else
	if (!stricmp(mapname, "$RSM_Normals_RT"))
		TexPic = CTexture::s_ptexRSMNormals;
	else
	if (!stricmp(mapname, "$RSM_Depth_RT"))
		TexPic = CTexture::s_ptexRSMDepth;
  else
  if (!stricmp(mapname, "$HDRTargetEncoded"))
    TexPic = CTexture::s_ptexHDRTargetEncoded;

  return TexPic;
}

const char *CShaderMan::mfTemplateTexIdToName(int Id)
{
  switch(Id)
  {
  case EFTT_DIFFUSE:
    return "Diffuse";
  case EFTT_GLOSS:
    return "Gloss";
  case EFTT_BUMP:
    return "Bump";
  case EFTT_ENV:
    return "Environment";
  case EFTT_SUBSURFACE:
    return "SubSurface";
  case EFTT_CUSTOM:
    return "CustomMap";
  case EFTT_CUSTOM_SECONDARY:
    return "CustomSecondaryMap";
  case EFTT_DETAIL_OVERLAY:
    return "Detail";
  case EFTT_OPACITY:
    return "Opacity";
  case EFTT_DECAL_OVERLAY:
    return "Decal";
  default:
    return "Unknown";
  }
  return "Unknown";
}

int CShaderMan::mfReadTexSequence(STexSamplerRT *smp, const char *na, byte eTT, int Flags)
{
  char prefix[_MAX_PATH];
  char postfix[_MAX_PATH];
  char *nm;
  int i, j, l, m;
  char nam[_MAX_PATH];
  int n;
  CTexture *tx, *tp;
  int startn, endn, nums;
  char name[_MAX_PATH];

  tx = NULL;

	if (smp->m_pAnimInfo)
	{
		assert(0);
		return 0;
	}

  strcpy_s(name, na);
  const char *ext = fpGetExtension (na);
  fpStripExtension(name, name);

  char chSep = '#';
  nm = strchr(name, chSep);
  if (!nm)
  {
    nm = strchr(name, '$');
    if (!nm)
      return 0;
    chSep = '$';
  }

  float fSpeed = 0.05f;
  {
    char nName[_MAX_PATH];
    strcpy(nName, name);
    nm = strchr(nName, '(');
    if (nm)
    {
      name[nm-nName] = 0;
      char *speed = &nName[nm-nName+1];
      if(nm=strchr(speed, ')'))
        speed[nm-speed] = 0;
      fSpeed = (float)atof(speed);
    }
  }

  j = 0;
  n = 0;
  l = -1;
  m = -1;
  while (name[n])
  {
    if (name[n] == chSep)
    {
      j++;
      if (l == -1)
        l = n;
    }
    else
    if (l >= 0 && m < 0)
      m = n;
    n++;
  }
  if (!j)
    return 0;

  strncpy(prefix, name, l);
  prefix[l] = 0;
  char dig[_MAX_PATH];
  l = 0;
  if (m < 0)
  {
    startn = 0;
    endn = 999;
    postfix[0] = 0;
  }
  else
  {
    while(isdigit((unsigned char)name[m]))
    {
      dig[l++] = name[m];
      m++;
    }
    dig[l] = 0;
    startn = strtol(dig, NULL, 10);
    m++;

    l = 0;
    while(isdigit((unsigned char)name[m]))
    {
      dig[l++] = name[m];
      m++;
    }
    dig[l] = 0;
    endn = strtol(dig, NULL, 10);

    strcpy(postfix, &name[m]);
  }

  nums = endn-startn+1;

  n = 0;
  char frm[256];
  char frd[4];

  frd[0] = j + '0';
  frd[1] = 0;

  strcpy(frm, "%s%.");
  strcat(frm, frd);
  strcat(frm, "d%s%s");
	STexAnim *ta = NULL;
  for (i=0; i<nums; i++)
  {
    sprintf(nam, frm, prefix, startn+i, postfix, ext);
    tp = (CTexture*)gRenDev->EF_LoadTexture(nam, Flags);
    if (!tp || !tp->IsLoaded())
    {
      if (tp)
        tp->Release();
      break;
    }
		if(!ta)
		{
			ta = new STexAnim; 
			ta->m_bLoop = true;
			ta->m_Time = fSpeed;
		}

		ITexture *pTex = (ITexture *)tp;
		ta->m_TexPics.AddElem(tp);
    n++;
  }

	if(ta)
	{
		ta->m_NumAnimTexs = ta->m_TexPics.Num();
		smp->m_pAnimInfo = ta;

		//Don't think this is ever set
		SAFE_RELEASE(smp->m_pTex);

		// this appears to always get overwritten, and so shouldn't be needed
//		smp->m_pTex = ta->m_TexPics[0];
//		smp->m_pTex->AddRef();
	}

  return n;
}

CTexture *CShaderMan::mfTryToLoadTexture(const char *nameTex, STexSamplerRT *smp, int Flags, byte eTT)
{
  CTexture *tx = NULL;                    
  if (nameTex && strchr(nameTex, '#')) // test for " #" to skip max material names
  {
    int n = mfReadTexSequence(smp, nameTex, eTT, Flags);
  }
  if (!tx)
  {
    tx = (CTexture *)gRenDev->EF_LoadTexture(nameTex, Flags);
  }

  return tx;
}

CTexture *CShaderMan::mfLoadResourceTexture(const char *nameTex, const char *path, int Flags, byte eTT, SEfResTexture *Tex)
{
  Flags &= ~FT_FILTER_MASK;
  if (Tex)
  {
    STexState ST;
    ST.SetFilterMode(Tex->m_Filter);
    ST.SetClampMode(Tex->m_bUTile ? TADDR_WRAP : TADDR_CLAMP, Tex->m_bVTile ? TADDR_WRAP : TADDR_CLAMP, Tex->m_bUTile ? TADDR_WRAP : TADDR_CLAMP);
    Tex->m_Sampler.m_nTexState = CTexture::GetTexState(ST);
  }
	CTexture *tx = mfTryToLoadTexture(nameTex, Tex ? &Tex->m_Sampler : NULL, Flags, eTT);

  return tx;
}

#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
void Process_DDNDIF_Name( char szOutName[256], CTexture *pTex )
{
	if(!pTex || (pTex->GetFlags()&FT_FILESINGLE)!=0)		// build process can tag assets so we can avoid loading additionally files
		return;

	const char *const szSrcName = pTex->GetSourceName();
	if(!szSrcName)
		return;

	const char *str = CryStringUtils::stristr(szSrcName, "_ddn");

	if(!str)
		return;

	const size_t nSize = (size_t)(str - szSrcName);

	// make sure to add only 'ddndif', if texture filename hasn't got ddndif
	if(!CryStringUtils::stristr(szSrcName, "_ddndif")) 
	{
		memcpy_s(szOutName, 256, szSrcName, nSize);
		memcpy_s(&szOutName[nSize], 256 - nSize, "_ddndif", 7);
		strcpy_s(&szOutName[nSize+7], 256 - nSize - 7, ".tif");
	}
	else
		strcpy_s(szOutName, 256, szSrcName);  

	if(gEnv->pCryPak->IsFileExist(szOutName))
		strcpy_s(&szOutName[nSize+7], 256 - nSize - 7,".dds");
	else
		*szOutName = 0;
}

static bool FindDisplTexture(const char* const pSrcName, char* pOutName, const size_t sizeOutName)
{
	if (pSrcName && pOutName && sizeOutName)
	{
		const char* pDDNSuffix = CryStringUtils::stristr(pSrcName, "_ddn");
		if (pDDNSuffix)
		{
			static const char pDisplSuffix[] = "_displ";
			static const size_t lenDisplSuffix = sizeof(pDisplSuffix) / sizeof(pDisplSuffix[0]) - 1;

#if defined(WIN32) || defined(WIN64) || defined(gringo)
			static const char pExt[] = ".dds";
			static const size_t lenExt = sizeof(pExt) / sizeof(pExt[0]) - 1;
#else
			static const char pExt[] = ".dds.0";
			static const size_t lenExt = sizeof(pExt) / sizeof(pExt[0]) - 1;
#endif

			const size_t namePatchPos = (size_t) (pDDNSuffix - pSrcName);
			if (namePatchPos + lenDisplSuffix + lenExt < sizeOutName)
			{
				memcpy(pOutName, pSrcName, namePatchPos);
				strcpy_s(&pOutName[namePatchPos], sizeOutName - namePatchPos, pDisplSuffix);
				strcpy_s(&pOutName[namePatchPos + lenDisplSuffix], sizeOutName - namePatchPos - lenDisplSuffix, pExt);
				if (gEnv->pCryPak->IsFileExist(pOutName))
				{
#if !(defined(WIN32) || defined(WIN64) || defined(gringo))
					pOutName[namePatchPos + lenDisplSuffix + lenExt - 2] = '\0';
#endif
					return true;
				}
#if defined(WIN32) || defined(WIN64)
				else if (gEnv->IsEditor())
				{
					const char* pDefExt = PathUtil::GetExt(pDDNSuffix);
					pDefExt = (pDefExt && *pDefExt) ? --pDefExt : ".tif";
					const size_t lenDefExt = strlen(pDefExt);
					if (namePatchPos + lenDisplSuffix + lenDefExt < sizeOutName)
					{
						strcpy_s(&pOutName[namePatchPos + lenDisplSuffix], sizeOutName - namePatchPos - lenDisplSuffix, pDefExt);
						if (gEnv->pCryPak->IsFileExist(pOutName))
						{
							return true;
						}
					}
				}
#endif
			}
		}

		*pOutName = '\0';
	}

	return false;
}
#endif

void CShaderMan::mfRefreshResources(SRenderShaderResources *Res, const bool bLoadNormalAlpha )
{
  int i;
  const char *patch = Res->m_TexturePath.c_str();
  if (Res)
  {
    for (i=0; i<EFTT_MAX; i++)
    {
			SEfResTexture *Tex = NULL;
			int Flags = 0;
      if (i == EFTT_BUMP)
      {
        if ((!Res->m_Textures[EFTT_BUMP] || Res->m_Textures[EFTT_BUMP]->m_Name.empty()))
          continue;

				Flags |= FT_TEX_NORMAL_MAP;
        if (!Res->m_Textures[EFTT_BUMP])
          Res->AddTextureMap(EFTT_BUMP);
        Tex = Res->m_Textures[EFTT_BUMP];
        if (!Tex->m_Sampler.m_pTex || !Tex->m_Sampler.m_pTex->IsTextureLoaded())
        {
          if (!Tex->m_Name.empty())
            Tex->m_Sampler.m_pTex = mfLoadResourceTexture(Tex->m_Name.c_str(), patch, Tex->m_Sampler.GetTexFlags() | Flags, eTT_2D, Tex);
          if (Tex->m_Sampler.m_pTex && !Tex->m_Sampler.m_pTex->IsTextureLoaded())
            Tex->m_Sampler.m_pTex = CTexture::s_ptexFlatBump;
        }
        continue;
      }
      else
			if (i == EFTT_BUMP_HEIGHT)
			{
				if (!bLoadNormalAlpha)
					continue;
				if (!Res->m_Textures[EFTT_BUMP] || !Res->m_Textures[EFTT_BUMP]->m_Sampler.m_pTex)
					continue;

				{
					const SEfResTexture* pBumpHeightTex = Res->m_Textures[EFTT_BUMP_HEIGHT];
					if (pBumpHeightTex)
					{
						const char* pBumpHeightFileName = !pBumpHeightTex->m_Name.empty() ? pBumpHeightTex->m_Name.c_str() : 0;
						if (pBumpHeightFileName)
						{
							Tex = Res->m_Textures[EFTT_BUMP_HEIGHT];
							if (!Tex->m_Sampler.m_pTex || !Tex->m_Sampler.m_pTex->IsTextureLoaded())
								Tex->m_Sampler.m_pTex = mfLoadResourceTexture(pBumpHeightFileName, patch, Tex->m_Sampler.GetTexFlags() | Flags, eTT_2D, Tex);
							continue;
						}
					}
				}

				// we load the alpha channel from the normal map (e.g. attached L8 for 3DC)
				CTexture *pTexN = Res->m_Textures[EFTT_BUMP]->m_Sampler.m_pTex;
				char nameDispl[256]; nameDispl[0] = 0;
#if (defined(DIRECT3D10) || defined(DIRECT3D9)) && (defined(WIN32) || defined(WIN64) || defined(gringo))
				if (!FindDisplTexture(Res->m_Textures[EFTT_BUMP]->m_Name.c_str(), nameDispl, sizeof(nameDispl) / sizeof(nameDispl[0])) && !(pTexN->GetFlags() & FT_HAS_ATTACHED_ALPHA))
#endif
					continue;
				Flags = !nameDispl[0] ? FT_ALPHA : 0;
				if (!Res->m_Textures[EFTT_BUMP_HEIGHT])
					Res->AddTextureMap(EFTT_BUMP_HEIGHT);
				Tex = Res->m_Textures[EFTT_BUMP_HEIGHT];

				CTexture* bhTex = Tex->m_Sampler.m_pTex;

				if (!bhTex || !bhTex->IsTextureLoaded())
					bhTex = mfLoadResourceTexture(nameDispl[0] ? nameDispl : pTexN->GetSourceName(), patch, Tex->m_Sampler.GetTexFlags() | Flags, eTT_2D, Tex);

				Res->m_Textures[EFTT_BUMP]->CopyTo(Res->m_Textures[EFTT_BUMP_HEIGHT]);
				SAFE_RELEASE(Tex->m_Sampler.m_pITex);
				Tex->m_Sampler.m_pTex = bhTex;
				continue;
			}
      if (i == EFTT_BUMP_DIFFUSE)
      {
        char nameBump[256];
        char nameNorm[256];
        nameBump[0] = 0;
        nameNorm[0] = 0;

#if !defined(PS3) && !defined(XENON) && !defined(CAFE)
				// Check if we have a ddndiff tif file to load
				if (!Res->IsEmpty(EFTT_BUMP))
					Process_DDNDIF_Name(nameBump,Res->m_Textures[EFTT_BUMP]->m_Sampler.m_pTex);
#endif

				if (nameBump[0] || nameNorm[0])
        {
          Flags |= FT_TEX_NORMAL_MAP;
          if (!Res->m_Textures[EFTT_BUMP_DIFFUSE])
            Res->AddTextureMap(EFTT_BUMP_DIFFUSE);
          if (nameBump[0] && nameNorm[0])
          {
            char fullname[256];
            sprintf(fullname, "%s+norm_%s", nameBump, nameNorm);
            Res->m_Textures[EFTT_BUMP_DIFFUSE]->m_Sampler.m_pTex = mfLoadResourceTexture(fullname, patch, Res->m_Textures[EFTT_BUMP]->m_Sampler.GetTexFlags() | Flags, eTT_2D, Res->m_Textures[EFTT_BUMP_DIFFUSE]);
          }
          Tex = Res->m_Textures[EFTT_BUMP_DIFFUSE];
          if (!Tex->m_Sampler.m_pTex || !Tex->m_Sampler.m_pTex->IsTextureLoaded())
          {
            if (nameBump[0])
              Tex->m_Sampler.m_pTex = mfLoadResourceTexture(nameBump, patch, Res->m_Textures[EFTT_BUMP]->m_Sampler.GetTexFlags() | Flags, eTT_2D, Tex);
            else
            if (nameNorm[0])
              Tex->m_Sampler.m_pTex = mfLoadResourceTexture(nameNorm, patch, Res->m_Textures[EFTT_BUMP]->m_Sampler.GetTexFlags() | Flags, eTT_2D, Tex);
            if (!Tex->m_Sampler.m_pTex || !Tex->m_Sampler.m_pTex->IsTextureLoaded())
            {
              SAFE_RELEASE(Tex->m_Sampler.m_pTex);
            }
          }
        }
      }
      Tex = Res->m_Textures[i];
      if (!Tex)
        continue;
			
      if (!Tex->m_Sampler.m_pTex)
      {
				if (Tex->m_Sampler.m_eTexType == eTT_NearestCube)
				{
					Tex->m_Sampler.m_pTex = CTexture::s_ptexFromObjCM;
				}
				else
        if (Tex->m_Sampler.m_eTexType == eTT_AutoCube || Tex->m_Sampler.m_eTexType == eTT_Auto2D)
        {
          if (i == EFTT_ENV || i == EFTT_DIFFUSE)
          {
            STexState ST;
            ST.SetFilterMode(Tex->m_Filter);
            ST.SetClampMode(Tex->m_bUTile ? TADDR_WRAP : TADDR_CLAMP, Tex->m_bVTile ? TADDR_WRAP : TADDR_CLAMP, Tex->m_bUTile ? TADDR_WRAP : TADDR_CLAMP);
            Tex->m_Sampler.m_nTexState = CTexture::GetTexState(ST);
            SAFE_RELEASE(Tex->m_Sampler.m_pTarget);
            Tex->m_Sampler.m_pTarget = new SHRenderTarget;
            const char* pExt = fpGetExtension(Tex->m_Name.c_str());
						if (pExt && (!stricmp(pExt, ".swf") || !stricmp(pExt, ".gfx") || !stricmp(pExt, ".usm") || !stricmp(pExt, ".ui")))
            {
              Tex->m_Sampler.m_pTarget->m_refSamplerID = i;
              if (CRenderer::CV_r_DynTexSourceUseSharedRT == 1)
                Tex->m_Sampler.m_pDynTexSource = new CFlashTextureSourceSharedRT(Tex->m_Name.c_str());
              else
                Tex->m_Sampler.m_pDynTexSource = new CFlashTextureSource(Tex->m_Name.c_str());
            }
            else
            {
              if (Tex->m_Sampler.m_eTexType == eTT_AutoCube)
              {
                Tex->m_Sampler.m_pTex = CTexture::s_ptexRT_CM;
                Tex->m_Sampler.m_pTarget->m_pTarget[0] = CTexture::s_ptexRT_CM;
              }
              else
              {
                Tex->m_Sampler.m_pTex = CTexture::s_ptexRT_2D;
                Tex->m_Sampler.m_pTarget->m_pTarget[0] = CTexture::s_ptexRT_2D;
              }		
            }
            Tex->m_Sampler.m_pTarget->m_bTempDepth = true;
            Tex->m_Sampler.m_pTarget->m_eOrder = eRO_PreProcess;
            Tex->m_Sampler.m_pTarget->m_eTF = eTF_A8R8G8B8;
            Tex->m_Sampler.m_pTarget->m_nIDInPool = -1;
            Tex->m_Sampler.m_pTarget->m_nFlags |= FRT_RENDTYPE_RECURSIVECURSCENE | FRT_CAMERA_CURRENT;
            Tex->m_Sampler.m_pTarget->m_nFlags |= FRT_CLEAR_DEPTH | FRT_CLEAR_STENCIL | FRT_CLEAR_COLOR;
          }
        }
        else
        if (Tex->m_Sampler.m_eTexType == eTT_User)
          Tex->m_Sampler.m_pTex = NULL;
        else
        {
          Tex->m_Sampler.m_pTex = mfLoadResourceTexture(Tex->m_Name.c_str(), patch, Tex->m_Sampler.GetTexFlags() | Flags, Tex->m_Sampler.m_eTexType, Tex);
          /*if (Tex->m_Sampler.m_pTex && Tex->m_Sampler.m_pTex->IsTextureLoaded())
          {
            if (i == EFTT_DIFFUSE)
              Tex->m_Sampler.m_pTex->SetFlags(FT_TEX_DIFFUSE);
          }*/
        }
      }

			// assign streaming priority based on the importance (sampler slot)
			if(Tex && Tex->m_Sampler.m_pITex && Tex->m_Sampler.m_pITex->IsTextureLoaded() && Tex->m_Sampler.m_pITex->IsStreamedVirtual())
			{
				CTexture* tp = (CTexture*)Tex->m_Sampler.m_pITex;
				tp->SetStreamingPriority(EFTT_MAX - i);
			}

			//if (i == EFTT_DIFFUSE)
			//{
			//	CTexture* pTex = (CTexture*) Tex->m_Sampler.m_pTex;
			//	if (pTex  && pTex->UseDecalBorderCol())
			//	{
			//		STexState ST;
			//		ST.SetFilterMode(Tex->m_Filter);
			//		ST.SetClampMode(TADDR_BORDER, TADDR_BORDER, TADDR_BORDER);
			//		ST.SetBorderColor(ColorF(1,1,1,0).pack_argb8888());
			//		Tex->m_Sampler.m_nTexState = CTexture::GetTexState(ST);
			//	}
			//}
    }
  }
#if defined (DIRECT3D10) && !defined(PS3) && !defined(CAFE)
  if (Res->m_Textures[EFTT_CUSTOM_SECONDARY] && Res->m_Textures[EFTT_CUSTOM_SECONDARY]->m_Sampler.m_pTex)
  {
    CTexture *pTexN = Res->m_Textures[EFTT_CUSTOM_SECONDARY]->m_Sampler.m_pTex;
    char nameDispl[256]; nameDispl[0] = 0;
		// Check if we have a displ tif file to load
	if (FindDisplTexture(Res->m_Textures[EFTT_CUSTOM_SECONDARY]->m_Name.c_str(), nameDispl, sizeof(nameDispl) / sizeof(nameDispl[0])))
	{
		int Flags = 0;
		if (!Res->m_Textures[EFTT_SUBSURFACE])
			Res->AddTextureMap(EFTT_SUBSURFACE);
		SEfResTexture *Tex = Res->m_Textures[EFTT_SUBSURFACE];
		if (!Tex->m_Sampler.m_pTex || !Tex->m_Sampler.m_pTex->IsTextureLoaded())
			Tex->m_Sampler.m_pTex = mfLoadResourceTexture(nameDispl, patch, Tex->m_Sampler.GetTexFlags() | Flags, eTT_2D, Tex);
	}
  }
#endif
}

#endif
